/****************************************************************************
 *
 *   Copyright (C) 2024 PX4 Development Team. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 * 3. Neither the name PX4 nor the names of its contributors may be
 *    used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 ****************************************************************************/

/**
 * @file lock_guard.hpp
 * @brief C++ RAII-style mutex lock guard
 *
 * This header provides a C++ class-based RAII (Resource Acquisition Is Initialization)
 * pattern for automatic mutex management. The lock is automatically acquired
 * when the object is created and released when the object is destroyed.
 *
 * This is the C++ version that provides TRUE RAII with full support for all
 * control flow statements (return, break, continue, goto, exceptions).
 *
 * @author PX4 Development Team
 */

#pragma once

#include "FreeRTOS.h"
#include "semphr.h"

/**
 * @class LockGuard
 * @brief RAII-style lock guard for FreeRTOS mutexes
 *
 * This class provides automatic mutex locking and unlocking using C++ RAII.
 * The mutex is locked in the constructor and automatically unlocked in the destructor,
 * ensuring proper cleanup even with early returns, breaks, continues, or exceptions.
 *
 * Usage:
 * @code
 * SemaphoreHandle_t my_mutex = xSemaphoreCreateMutex();
 *
 * {
 *     LockGuard lock(my_mutex);
 *     // Critical section - mutex is locked here
 *     // Do some work...
 *     if (error) {
 *         return;  // Mutex is automatically unlocked
 *     }
 *     for (int i = 0; i < 10; i++) {
 *         if (condition) {
 *             break;  // Mutex is automatically unlocked
 *         }
 *     }
 *     // More work...
 * }
 * // Mutex is automatically unlocked here
 * @endcode
 *
 * @note This class uses C++ RAII, which provides TRUE automatic resource management.
 * @note The mutex is taken with portMAX_DELAY, meaning it will wait indefinitely
 *       until the mutex is available.
 * @note This class is non-copyable and non-movable to prevent accidental double-unlock.
 */
class LockGuard
{
public:
	/**
	 * @brief Constructor - acquires the mutex
	 * @param mutex The FreeRTOS mutex handle to lock
	 */
	explicit LockGuard(SemaphoreHandle_t &mutex) :
		_mutex(mutex)
	{
		xSemaphoreTake(_mutex, portMAX_DELAY);
	}

	/**
	 * @brief Destructor - releases the mutex
	 */
	~LockGuard()
	{
		xSemaphoreGive(_mutex);
	}

	// Delete copy constructor and copy assignment
	LockGuard(const LockGuard &other) = delete;
	LockGuard &operator=(const LockGuard &other) = delete;

	// Delete move constructor and move assignment
	LockGuard(LockGuard &&other) = delete;
	LockGuard &operator=(LockGuard &&other) = delete;

private:
	SemaphoreHandle_t &_mutex;  ///< Reference to the mutex being guarded
};

/**
 * @class LockGuardTimeout
 * @brief RAII-style lock guard with timeout support
 *
 * Similar to LockGuard, but allows specifying a timeout for acquiring the mutex.
 * If the mutex cannot be acquired within the timeout, the block is skipped.
 *
 * Usage:
 * @code
 * SemaphoreHandle_t my_mutex = xSemaphoreCreateMutex();
 *
 * {
 *     LockGuardTimeout lock(my_mutex, pdMS_TO_TICKS(100));
 *     if (lock.locked()) {
 *         // Critical section - mutex was successfully acquired
 *     }
 * }
 * // Mutex is automatically unlocked here (if it was acquired)
 * @endcode
 */
class LockGuardTimeout
{
public:
	/**
	 * @brief Constructor - attempts to acquire the mutex with timeout
	 * @param mutex The FreeRTOS mutex handle to lock
	 * @param timeout The maximum time to wait for the mutex (in ticks)
	 */
	LockGuardTimeout(SemaphoreHandle_t &mutex, TickType_t timeout) :
		_mutex(mutex),
		_locked(xSemaphoreTake(_mutex, timeout) == pdTRUE)
	{
	}

	/**
	 * @brief Destructor - releases the mutex if it was acquired
	 */
	~LockGuardTimeout()
	{
		if (_locked) {
			xSemaphoreGive(_mutex);
		}
	}

	/**
	 * @brief Check if the mutex was successfully acquired
	 * @return true if the mutex is locked, false otherwise
	 */
	bool locked() const { return _locked; }

	// Delete copy and move operations
	LockGuardTimeout(const LockGuardTimeout &other) = delete;
	LockGuardTimeout &operator=(const LockGuardTimeout &other) = delete;
	LockGuardTimeout(LockGuardTimeout &&other) = delete;
	LockGuardTimeout &operator=(LockGuardTimeout &&other) = delete;

private:
	SemaphoreHandle_t &_mutex;  ///< Reference to the mutex being guarded
	bool _locked;               ///< Whether the mutex was successfully acquired
};

